package com.lijianpo.util.extension.datamasking.ser;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.lijianpo.util.extension.datamasking.annotation.Sensitive;

import java.io.IOException;

/**
 * 脱敏序列化实现
 * @author zhangyang
 * @date 2020/11/2 17:41
 */
public class SensitiveSerializer<Object> extends JsonSerializer<Object> implements ContextualSerializer {


    private BaseSensitiveSerializer _sensitiveSerializer;


    /**
     * Method that can be called to ask implementation to serialize
     * values of type this serializer handles.
     *
     * @param value       Value to serialize; can <b>not</b> be null.
     * @param gen         Generator used to output resulting Json content
     * @param serializers Provider that can be used to get serializers for
     */
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        _sensitiveSerializer.serialize(value, gen, serializers);
    }

    /**
     * Method called to see if a different (or differently configured) serializer
     * is needed to serialize values of specified property.
     * Note that instance that this method is called on is typically shared one and
     * as a result method should <b>NOT</b> modify this instance but rather construct
     * and return a new instance. This instance should only be returned as-is, in case
     * it is already suitable for use.
     *
     * @param prov     Serializer provider to use for accessing config, other serializers
     * @param property Method or field that represents the property
     *                 (and is used to access value to serialize).
     *                 Should be available; but there may be cases where caller cannot provide it and
     *                 null is passed instead (in which case impls usually pass 'this' serializer as is)
     * @return Serializer to use for serializing values of specified property;
     * may be this instance or a new instance.
     * @throws JsonMappingException
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (property != null) {
            Sensitive sensitiveInfo = getSensitiveInfo(property);
            if (sensitiveInfo != null) {
                _sensitiveSerializer = SensitiveSerializerFactory.createSerializer(sensitiveInfo, property);
                if (_sensitiveSerializer != null) {
                    return _sensitiveSerializer;
                }
            }
        }
        return prov.findNullValueSerializer(null);
    }

    private Sensitive getSensitiveInfo(BeanProperty property) {
        Sensitive sensitiveInfo = property.getAnnotation(Sensitive.class);
        if (sensitiveInfo == null) {
            sensitiveInfo = property.getContextAnnotation(Sensitive.class);
        }
        return sensitiveInfo;
    }
}
